home *** CD-ROM | disk | FTP | other *** search
/ Trading on the Edge / Trading On The Edge - CD-ROM Toolkit (Wayzata Technology)(2031)(1994).bin / mac / Mac_Files / Software Utilities / NN PreProcessing / FINCMD.C < prev    next >
C/C++ Source or Header  |  1992-09-25  |  53KB  |  1,767 lines

  1. /* 17:10 02-Jan-92  (fincmd.c)  Command Line Parser */
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include "fincmd.h"
  6.  
  7. /************************************************************************
  8.  * Copyright(C) 1992 High-Tech Communications.                          *
  9.  * 103 Buckskin Court, Sewickley, PA 15143                              *
  10.  *                                                                      *
  11.  * Written by Casimir C. Klimasauskas                                   *
  12.  *                                                                      *
  13.  * All rights reserved.  No part of this program may be reproduced,     *
  14.  * stored in a retrieval system, or tramsmitted, in any form or by any  *
  15.  * means, electronic, mechanical, photocopying, recording or otherwise  *
  16.  * without the prior written permission of the copyright owner,         *
  17.  * High-Tech Communications.                                            *
  18.  *                                                                      *
  19.  * These programs are supplied on an "as-is" basis with no warranties   *
  20.  * of fitness or operability, either express or implied.                *
  21.  *                                                                      *
  22.  ************************************************************************
  23.  */
  24.  
  25. /************************************************************************
  26.  *                                    *
  27.  *    fincmd - Command Line Parser & Data Display Routines        *
  28.  *                                    *
  29.  ************************************************************************
  30.     ParseLineI() Syntax:
  31.     ?        - prints out all of the current variables
  32.     ?variable    - prints out values associated with this variable
  33.     name?        - prints out
  34.                 a) syntax associated with name if unique
  35.                 b) list of possible variables which match.
  36.     ??        - prints out syntax of all variables
  37.     command        - executes the command
  38.     variable value    - assigns value to variable
  39.     variable=value    - ditto
  40.  
  41.     For Future:
  42.     actually set flag bits for items converted so if there are more
  43.     than one optional item, each individually can be accounted for.
  44.  */
  45.  
  46. #ifdef    LOCAL
  47. #undef    LOCAL
  48. #endif
  49.  
  50. #ifdef    TESTCMD
  51. #define    LOCAL
  52. #else
  53. #define    LOCAL static
  54. #endif
  55.  
  56. /* --- Special Local Defines --- */
  57.  
  58. #define    TOKE_EOL    0    /* end of line */
  59. #define    TOKE_TRM    1    /* terminal character */
  60. #define    TOKE_STR    2    /* quoted string */
  61. #define    TOKE_CHR    3    /* single character (quoted) */
  62. #define    TOKE_INT    4    /* integer */
  63. #define    TOKE_FLT    5    /* floating point number */
  64. #define    TOKE_DBL    6    /* double precision number */
  65. #define    TOKE_LIT    7    /* literal */
  66.  
  67. #define    COMMENT    '!'        /* start of comment character */
  68.  
  69. static long ConvertedL = {0};    /* # of items converted (kludge) */
  70. /*   */
  71. /************************************************************************
  72.  *                                    *
  73.  *    Str2Str() - convert a character string to "C" format        *
  74.  *                                    *
  75.  ************************************************************************
  76.  
  77.     Escape sequences translated
  78.     \r, \n, \f, \b, \t, \', \", \\    - CR, LF, FF, BS, Tab, ', ", \
  79.     \xFF, \xF            - hex character
  80.     \o, \oo, \ooo            - octal character
  81.     ^a..z, ^A..Z            - control characters
  82.     ^^ = ^
  83.  
  84.     rc = Str2Str( dp, sp, fm )
  85.         dp - destination pointer (may be same as sp)
  86.         sp - source pointer
  87.         fm - format (0=translate escape chars)
  88.     rc = 0, all is well;
  89.       <> 0, error of some sort.
  90.  */
  91.  
  92. LOCAL int Str2Str( dp, sp, fm )    /* convert "c" style string */
  93. char        *dp;        /* destination pointer */
  94. char        *sp;        /* source pointer */
  95. int         fm;        /* format 0=translate escape chars */
  96. {
  97.     FAST int     rc;        /* return code */
  98.     FAST int     c;        /* work character */
  99.     FAST int     nc;        /* # of chars */
  100.     FAST int     wnc;        /* work # of chars */
  101.     FAST int     ac;        /* alternate char */
  102.     FAST char    *wsp;        /* work string pointer */
  103.  
  104.     rc = 0;
  105.     for( nc = 0; (c = *sp) != 0; sp++ ) {
  106.     if ( fm == 0 && c == '\\' ) {        /* special escape chars */
  107.         wnc = 0;
  108.         wsp = sp;
  109.         ac  = *++wsp;
  110.         c   = 0;
  111.         if ( '0' <= ac && ac <= '7' ) {
  112.         /* --- octal literal --- */
  113.         for(; (ac = *wsp) != '\0' && wnc < 3; wsp++, wnc++ ) {
  114.             if ( '0' <= ac && ac <= '7' )    ac -= '0';
  115.             else break;
  116.             c = (c << 3) | ac;
  117.         }
  118.         goto CleanChar;
  119.         } else if ( ac == 'x' || ac == 'X' ) {
  120.         /* --- hex literal --- */
  121.         for( wsp++; (ac = *wsp) != '\0' && wnc < 2; wsp++, wnc++ ) {
  122.             if ( '0'<=ac && ac<='9' )        ac -= '0';
  123.             else if ( 'a'<=ac && ac<='f' )    ac -= 'a'-10;
  124.             else if ( 'A'<=ac && ac<='F' )    ac -= 'A'-10;
  125.             else break;
  126.             c = (c << 4) | ac;
  127.         }
  128.         CleanChar:
  129.         if ( wnc == 0 ) {
  130.             rc = -1;        /* bad character */
  131.             c  = *sp;
  132.         } else {
  133.             c &= 0xff;
  134.             sp = wsp-1;
  135.         }
  136.         } else {
  137.         /* --- single escape character --- */
  138.         switch( ac ) {
  139.         case '^':    c = '^';    break;    /* Caret */
  140.         case 'r':    c = 0x0d;    break;    /* CR */
  141.         case 'n':    c = 0x0a;    break;    /* LF */
  142.         case 'f':    c = 0x0c;    break;    /* FF */
  143.         case 'b':    c = 0x08;    break;    /* BS */
  144.         case 't':    c = 0x09;    break;    /* tab */
  145.         case '\'':    c = '\'';    break;    /* single quote */
  146.         case '\"':    c = '\"';    break;    /* double quote */
  147.         case '\\':    c = '\\';    break;    /* back-slash */
  148.         default:    c = *sp; wsp = sp; rc = -1; break;
  149.         }
  150.         sp = wsp;
  151.         }
  152.     } else if ( fm == 0 && c == '^' ) {
  153.         wsp = sp;
  154.         ac  = *++wsp;        /* peek ahead one character */
  155.         wnc = 0;            /* translation flag */
  156.         if ( 'A' <= ac && ac <= 'Z' ) {
  157.         c = ac - 'A' + 1; wnc++;
  158.         } else if ( 'a' <= ac && ac <= 'z' ) {
  159.         c = ac - 'a' + 1; wnc++;
  160.         } else if ( '^' == ac ) {
  161.         c = '^'; wnc++;
  162.         }
  163.         if ( wnc )
  164.         sp = wsp;        /* valid translation */
  165.     }
  166.     *dp++ = c;
  167.     nc++;
  168.     }
  169.  
  170.     *dp = '\0';
  171.     return( rc );
  172. }
  173. /*   */
  174. /************************************************************************
  175.  *                                    *
  176.  *    NextToke() - Get & Interpret next token in input buffer        *
  177.  *                                    *
  178.  ************************************************************************
  179.     The buffer is parsed to see what follows.  It returns one of the
  180.     following return types and updates the buffer pointer to the next
  181.     non-blank character past it.
  182.  
  183.     TOKE_EOL - at end of line
  184.  
  185.     TOKE_TRM (CV_TokeLong)
  186.     terminator character    !, <null> or terminator character
  187.  
  188.  
  189.     TOKE_STR (CV_TokeString)
  190.     string            "...."    (when stored, 1st char is length)
  191.             or    "...""..."  (embedded quote)
  192.                 all characters accepted except <CR> & <LF>.
  193.                 "C" style escape sequences are converted.
  194.  
  195.     TOKE_CHR (CV_TokeLong & CV_TokeChar)
  196.     character        'c'    (quoted character)
  197.                 must be >= ' ', or use \r, \n, \f, \b, \t,
  198.                     \xFF, \ooo, \\, \'.
  199.  
  200.     TOKE_INT (CV_TokeLong)
  201.     decimal integer        [+/-][1..9][d...]    d: 0..9
  202.     octal integer        [+/-]0[d...]        d: 0..7
  203.     hex integer        [+/-]0x[d...]        d: 0..9, a..f, A..F
  204.     binary integer        [+/-]0b[d...]        d: 0..1
  205.  
  206.     TOKE_FLT (CV_TokeDBL)
  207.     float            [+/-][d...].[d..][E+/-d[..]]
  208.     TOKE_DBL (CV_TokeDBL)
  209.     double            [+/-][d...].[d..][D+/-d[..]]
  210.                 (default is "float" )
  211.  
  212.     TOKE_LIT (CV_TokeToke)
  213.     token            anything else.
  214.  */
  215.  
  216. LOCAL long    CV_TokeLong       = {0};   /* CV_Token as "long" */
  217. LOCAL double    CV_TokeDBL       = {0.};  /* CV_Token as "double" */
  218. LOCAL char    CV_TokeString[132] = {0};   /* CV_Token as "string" */
  219. LOCAL char    CV_TokeToke[132]   = {0};   /* CV_Token as literal string */
  220.  
  221. LOCAL int NextToke( spp, TermsP, tp )        /* get next token */
  222. char        **spp;        /* pointer to pointer to input string */
  223. char        *TermsP;    /* terminals */
  224. int        *tp;        /* pointer to return pointer */
  225. {
  226.     FAST int     rc;        /* return code */
  227.     FAST long     base;        /* current "base" */
  228.     FAST int     c, cn;        /* char, "numeric" character */
  229.     FAST int     decpt;        /* decimal points */
  230.     FAST int     exp;        /* exponent */
  231.     FAST int     sign, esign;    /* sign of item, exponent sign */
  232.     FAST int     gotdig;    /* got a digit */
  233.     FAST char    *sp;        /* work string pointer */
  234.     FAST char    *dp;        /* destination pointer */
  235.     FAST char    *sp0;        /* initial string pointer */
  236.     FAST char    *spToke;    /* token end of string pointer */
  237.     FAST char    *wsp;        /* work string pointer */
  238.     FAST int     aexp;        /* absolute exponent */
  239.     FAST double     wD;        /* work value */
  240.     char    CV_TokeChar[8];    /* CV_Token as "char" work area */
  241.     char    TermsCA[68];    /* local "terminators" */
  242.  
  243.  
  244.     /* --- initialize work variables --- */
  245.  
  246.     memset( TermsCA, 0, sizeof(TermsCA) );
  247.     TermsCA[0] = COMMENT;
  248.     if ( TermsP )
  249.     strncpy( &TermsCA[1], TermsP, sizeof(TermsCA)-2 );
  250.  
  251.     CV_TokeString[0] = 0;
  252.     CV_TokeString[1] = 0;
  253.     CV_TokeLong = 0;
  254.     CV_TokeDBL  = 0.0;
  255.     memset( (char *)CV_TokeToke, 0, sizeof(CV_TokeToke) );
  256.     sp        = *spp;
  257.     while( *sp && *sp <= ' ' ) sp++;        /* skip leading spaces */
  258.  
  259.     /* --- Check for end of line --- */
  260.  
  261.     if ( *sp == 0 ) {
  262.     rc = TOKE_EOL;                /* end of line */
  263.     goto Done;
  264.     }
  265.     sp0 = sp;                    /* first non-blank character */
  266.  
  267.     /* --- Check for "terminator" --- */
  268.  
  269.     if ( strchr(TermsCA,*sp) != (char *)0 ) {
  270.     rc = TOKE_TRM;                /* terminator */
  271.     CV_TokeLong = *sp & 0xff;        /* stay positioned there */
  272.     goto Done;
  273.     }
  274.  
  275.     /* --- set up token, regardless --- */
  276.  
  277.     wsp = &CV_TokeToke[1];
  278.     for( cn = 1; (c = *sp) > ' ' && strchr(TermsCA,c)==(char *)0; sp++ ) {
  279.     if ( cn < sizeof(CV_TokeToke)-1 )
  280.         *wsp++ = c;                /* stuff next char */
  281.     cn++;
  282.     }
  283.     *wsp = 0;
  284.     cn--;
  285.     CV_TokeToke[0] = cn;
  286.     spToke = sp;                /* save string for return */
  287.  
  288.     /* --- try for quoted string --- */
  289.  
  290.     sp        = sp0;
  291.     rc        = TOKE_STR;            /* quoted string */
  292.     wsp        = &CV_TokeString[1];
  293.     if ( *sp == '"' ) {
  294.     sp++;
  295.     for( cn = 0; (c = *sp) != 0; sp++, cn++ ) {
  296.         if ( c == '\r' || c == '\n' )
  297.         break;                /* bad string */
  298.         if ( c == '"' ) {            /* end of string ? */
  299.         if ( sp[1] > ' ' && sp[1] != '"' )
  300.              break;            /* bad string */
  301.         if ( sp[1] <= ' ' ) {        /* end of string */
  302.             /* --- map escape sequences --- */
  303.             *wsp = 0;            /* null terminate string */
  304.             Str2Str( &CV_TokeString[1], &CV_TokeString[1], 0 );
  305.             CV_TokeString[0] = strlen( &CV_TokeString[1] );
  306.             sp++;
  307.             goto Done;
  308.         }
  309.         }
  310.  
  311.         if ( cn < sizeof(CV_TokeString)-3 )
  312.         *wsp++ = c;
  313.         if ( c == '"' )
  314.         sp++;                /* skip double quote */
  315.     } 
  316.     }
  317.     CV_TokeString[0] = 0;
  318.  
  319.     /* --- try for quoted character --- */
  320.  
  321.     sp        = sp0;
  322.     rc        = TOKE_CHR;            /* quoted character */
  323.     memset( CV_TokeChar, 0, sizeof(CV_TokeChar) );
  324.     if ( *sp == '\'' ) {
  325.     for( cn = 0, sp++; (c = *sp) != '\0'; sp++ ) {
  326.         if ( c < ' ' || cn >= sizeof( CV_TokeChar )-2 )
  327.         break;                /* illegal */
  328.         if ( c == '\'' ) {
  329.         if ( cn == 0 ) break;        /* illegal */
  330.         if ( CV_TokeChar[cn-1] != '\\' ) {
  331.             /* --- hit end of string:  check for validity --- */
  332.             if ( Str2Str( &CV_TokeChar[0], &CV_TokeChar[0], 0 ) )
  333.             break;            /* illegal somehow */
  334.             if ( CV_TokeChar[1] != 0 )
  335.             break;            /* multi-char string */
  336.             CV_TokeLong = CV_TokeChar[0] & 0xff; /* force unsigned */
  337.             sp++;
  338.             goto Done;
  339.         }
  340.         }
  341.         CV_TokeChar[cn++] = c;
  342.         CV_TokeChar[cn] = 0;
  343.     }
  344.     }
  345.  
  346.     /* --- see if we have a "long" --- */
  347.  
  348.     sp        = sp0;                /* reset pointer */
  349.     rc        = TOKE_INT;            /* assume integer token */
  350.     base    = 10;                /* default base */
  351.     sign    = 0;                /* no leading sign */
  352.     CV_TokeLong    = 0;                /* token as long */
  353.     c = *sp;
  354.     if ( c == '+' || c == '-' ) {        /* take care of leading sign */
  355.     sign = (c == '+'? 1:-1);
  356.     c = *++sp;
  357.     }
  358.     if ( c == '0' ) {                /* leading zero special cases */
  359.     base = 8;
  360.     if ( sp[1] == 'x' || sp[1] == 'X' ) {
  361.         base = 16;
  362.         sp += 2;
  363.     } else if ( sp[1] == 'b' || sp[1] == 'B' ) {
  364.         base = 2;
  365.         sp += 2;
  366.     } else sp++;
  367.     }
  368.  
  369.     for( ; (c = *sp) > ' ' && strchr(TermsCA,c)==(char *)0; sp++ ) {
  370.     if ( '0' <= c && c <= '9' )        cn = c - '0';
  371.     else if ( 'a' <= c && c <= 'f' )    cn = c - 'a' + 10;
  372.     else if ( 'A' <= c && c <= 'F' )    cn = c - 'A' + 10;
  373.     else                    cn = -1;
  374.  
  375.     if ( cn < 0 || base <= cn ) {
  376.         rc = 0;
  377.         break;
  378.     }
  379.  
  380.     CV_TokeLong = (base * CV_TokeLong) + cn;
  381.     }
  382.  
  383.     if ( (*sp <= ' ' || strchr(TermsCA,*sp) != (char *)0)  && rc != 0 ) {
  384.     if ( sign < 0 )    CV_TokeLong = 0 - CV_TokeLong;
  385.     goto Done;                /* it is LONG !!! */
  386.     }
  387.     CV_TokeLong = 0;
  388.  
  389.     /* --- not long, try float or double --- */
  390.  
  391.     rc        = TOKE_FLT;            /* assume double */
  392.     sp        = sp0;                /* reset pointer */
  393.     sign    = 0;                /* no sign */
  394.     CV_TokeDBL    = 0.0;                /* token as double */
  395.     esign    = 0;                /* no exponent sign */
  396.     exp        = 0;                /* exponent value */
  397.     decpt    = -1;                /* no decimal point */
  398.     gotdig    = 0;                /* got a digit */
  399.     c        = *sp;                /* first character */
  400.     if ( c == '+' || c == '-' ) {
  401.     sign = (c == '+'? 1:-1);
  402.     c = *++sp;
  403.     }
  404.  
  405.     for( ; (c = *sp) > ' '; sp++ ) {
  406.     if ( c == '.' ) {
  407.         if ( decpt >= 0 ) {
  408.         NotDbl:
  409.         rc = 0;
  410.         break;
  411.         }
  412.         decpt = 0;
  413.     } else if ( '0' <= c && c <= '9' ) {
  414.         cn = c - '0';
  415.         CV_TokeDBL = (CV_TokeDBL * 10.) + (double)(cn);
  416.         if ( decpt >= 0 ) decpt++;
  417.         gotdig++;
  418.     } else if ( c == 'd' || c == 'D' || c == 'e' || c == 'E' ) {
  419.         /* exponent */
  420.         if ( gotdig == 0 )
  421.         goto NotDbl;
  422.         rc = (c == 'd' || c == 'D' )? TOKE_DBL:TOKE_FLT;
  423.         c = *++sp;
  424.         if ( c == '+' || c == '-' ) {
  425.         esign = (c == '+'? 1:-1);
  426.         sp++;
  427.         }
  428.         while( '0' <= *sp && *sp <= '9' ) {
  429.         exp = (10 * exp) + (*sp - '0');
  430.         sp++;
  431.         }
  432.         if ( esign < 0 ) exp = 0 - exp;
  433.         break;
  434.     } else {
  435.         goto NotDbl;            /* bad character */
  436.     }
  437.     }
  438.  
  439.     if ( (*sp <= ' ' || strchr(TermsCA,*sp) != (char *)0) && rc != 0 ) {
  440.     if ( decpt > 0 )
  441.         exp -= decpt;
  442.     /* --- Special conversion to minimize rounding errors --- */
  443.     aexp = (exp >= 0? exp:(-exp));
  444.     wD = 1.0;
  445.     if ( aexp > 40 ) aexp = 40;
  446.     while( aexp > 5 ) { wD *= 100000.; aexp -= 5; }    /* no rounding */
  447.     while( aexp > 0 ) { wD *=     10.; aexp -= 1; }    /* no rounding */
  448.     if (      exp > 0 ) { CV_TokeDBL *= wD; }
  449.     else if ( exp < 0 ) { CV_TokeDBL /= wD; }
  450.     if ( sign < 0 )    CV_TokeDBL = 0. - CV_TokeDBL;
  451.  
  452.     goto Done;                /* it is FLOAT !!! */
  453.     }
  454.     CV_TokeDBL = 0.0;
  455.  
  456.     /* --- must be a regular token --- */
  457.  
  458.     rc = TOKE_LIT;
  459.     sp = spToke;
  460.  
  461. Done:
  462.     while( *sp && *sp <= ' ' ) sp++;        /* skip trailing spaces */
  463.     *spp = sp;
  464.     if ( tp ) *tp  = rc;
  465.     return( rc );
  466. }
  467. /*   */
  468. /************************************************************************
  469.  *                                    *
  470.  *    SearchLitTableP() - Search literal table            *
  471.  *                                    *
  472.  ************************************************************************
  473.      Searches literal table until string is found or end of table.
  474.      If end of table is reached, NULL (fail) is returned.
  475.  */
  476.  
  477. LOCAL LIT *SearchLitTableP( msP, LitTabP )    /* search literal table */
  478. char        *msP;        /* string to search for */
  479. LIT        *LitTabP;    /* command table pointer */
  480. {
  481.     FAST int     ca, cb;    /* compare characters */
  482.     FAST char    *sP;        /* work char pointer */
  483.     FAST char    *aP;        /* alt work character */
  484.     FAST LIT    *litP;        /* work command pointer */
  485.     FAST int     nlI;        /* near literal counter */
  486.     FAST LIT    *nlP;        /* near literal pointer */
  487.  
  488.     if ( LitTabP == (LIT *)0 || msP == (char *)0 )
  489.     goto Fail;
  490.  
  491.     for( sP = msP; (ca = *sP) != 0; sP++ )    /* convert to lower case */
  492.     if ( 'A' <= ca && ca <= 'Z' ) *sP = ca - ('A'-'a');
  493.  
  494.     nlP = (LIT *)0;
  495.     nlI = 0;
  496.     for( litP = LitTabP; (aP = litP->LNameCP) != (char *)0; litP++ ) {
  497.     for( sP = msP;; sP++, aP++) {
  498.         ca = *sP;
  499.         cb = *aP;
  500.         if ( ca == 0 ) {
  501.         if ( cb == 0 ) return( litP );    /* exact match */
  502.         nlI++;                /* count "near" match */
  503.         nlP = litP;            /* save ptr to last */
  504.         break;
  505.         }
  506.         if ( ca != cb ) {
  507.         if ( 'A' <= cb && cb <= 'Z' ) {
  508.             cb -= 'A' - 'a';
  509.             if ( ca != cb ) break;
  510.         } else break;
  511.         }
  512.     }
  513.     }
  514.     if ( nlI == 1 ) return( nlP );        /* near & unique */
  515.  
  516. Fail:
  517.     return( (LIT *)0 );
  518. }
  519. /*   */
  520. /************************************************************************
  521.  *                                    *
  522.  *    SearchCmdTableP() - Search command table            *
  523.  *                                    *
  524.  ************************************************************************
  525.     Searches command table until string is found or end of table
  526.     (null string pointer) is reached.
  527.  
  528.     returns pointer into command table or NULL (fail).
  529.  */
  530.  
  531. LOCAL CMD *SearchCmdTableP( msP, CmdTabP, ModeI )    /* search command table */
  532. char        *msP;        /* string to search for */
  533. CMD        *CmdTabP;    /* command table pointer */
  534. int         ModeI;        /* =0, exact; =1, partial */
  535. {
  536.     FAST int     ca, cb;    /* compare characters */
  537.     FAST char    *sP;        /* work char pointer */
  538.     FAST char    *aP;        /* alt work character */
  539.     FAST CMD    *cmdP;        /* work command pointer */
  540.     FAST CMD    *nlP;        /* near match */
  541.     FAST int     nlI;        /* counter for near match */
  542.  
  543.     if ( CmdTabP == (CMD *)0 || msP == (char *)0 )
  544.     goto Fail;
  545.  
  546.     for( sP = msP; (ca = *sP) != 0; sP++ )    /* convert to lower case */
  547.     if ( 'A' <= ca && ca <= 'Z' ) *sP = ca - ('A'-'a');
  548.  
  549.     nlI = 0;
  550.     nlP = (CMD *)0;
  551.     for( cmdP = CmdTabP; (aP = cmdP->CNameCP) != (char *)0; cmdP++ ) {
  552.     for( sP = msP;; sP++, aP++) {
  553.         ca = *sP;
  554.         cb = *aP;
  555.         if ( ca == 0 ) {
  556.         if ( cb == 0 || ModeI )
  557.             return( cmdP );        /* exact match or partial request */
  558.         nlI++;                /* count near hits */
  559.         nlP = cmdP;            /* save pointer to last */
  560.         break;
  561.         }
  562.         if ( ca != cb ) {
  563.         if ( 'A' <= cb && cb <= 'Z' ) {
  564.             cb -= 'A' - 'a';        /* try case insensitive */
  565.             if ( ca != cb ) break;
  566.         } else break;
  567.         }
  568.     }
  569.     }
  570.  
  571.     if ( nlI == 1 ) return( nlP );        /* one "near" match */
  572.  
  573. Fail:
  574.     return( (CMD *)0 );
  575. }
  576. /*   */
  577. /************************************************************************
  578.  *                                    *
  579.  *    StoreValueI() - store a value into a data element        *
  580.  *                                    *
  581.  ************************************************************************
  582.      rc = 0: all is well;  else, error & message printed.
  583.  */
  584.  
  585. int StoreValueI( cP, inP, dV )        /* store a value */
  586. FAST char    *cP;        /* data pointer (this item) */
  587. FAST INPUT    *inP;        /* input structure */
  588. FAST double     dV;        /* value to store */
  589. {
  590.     FAST UVP     p;        /* universal pointer */
  591.     FAST int     SizeI;        /* size of item */
  592.     FAST long     vL;        /* work long */
  593.     FAST int     TypeI;        /* type of item */
  594.     char     buf[80];    /* message buffer */
  595.  
  596.     if ( inP == (INPUT *)0 )
  597.     return( -1 );
  598.  
  599.     if ( cP == (char *)0 ) cP = (char *)inP->IValP;
  600.  
  601.     if ( (p.cP  = cP) == (char *)0 || (SizeI = inP->ISizeI) == 0 ) {
  602.     Fail:
  603.     sprintf( buf, "** Store Failure ptr=%08lx size=%d func i=0x%02x\n",
  604.         p.cP, SizeI, inP->IInFuncC & 0xff );
  605.     MsgER( buf );
  606.     return( -1 );
  607.     }
  608.  
  609.     TypeI = (inP->IInFuncC & IO_MASK);
  610.     if ( TypeI == IO_FLT ) {
  611.     /* --- NOTE: on some systems (transputers)
  612.      *   sizeof(float) == sizeof(double) 
  613.      */
  614.     if (      SizeI == sizeof(float)  )    *p.fP = dV;
  615.     else if ( SizeI == sizeof(double) )    *p.dP = dV;
  616.     else goto Fail;
  617.     } else if ( TypeI == IO_INT || TypeI == IO_BIT ) {
  618.     if (      dV < -((double)0x7fffffffL) )    vL = 0x80000000L;
  619.     else if ( dV >  ((double)0x7fffffffL) ) vL = 0x7fffffffL;
  620.     else                    vL = (dV < 0.0? (dV - 0.5):(dV + 0.5));
  621.     switch( SizeI ) {
  622.     case sizeof(char):    *p.cP = vL;    break;
  623.     case sizeof(short):    *p.sP = vL;    break;
  624.     case sizeof(long):    *p.lP = vL;    break;
  625.     default:        goto Fail;
  626.     }
  627.     } else goto Fail;
  628.  
  629.     return( 0 );
  630. }
  631. /*   */
  632. /************************************************************************
  633.  *                                    *
  634.  *    ParseBitsI() - Parse the "or" of several bit masks        *
  635.  *                                    *
  636.  ************************************************************************
  637.      start with the first element in the list.
  638.      Try looking it up in the literal table or converting it.
  639.  
  640.      NOTE: This makes the assumption that a literal has been detected,
  641.      and it did not match something in the table.  So, this will
  642.      attempt to break it into a series of smaller units which are
  643.      merged together as "bits".
  644.  */
  645.  
  646. LOCAL int ParseBitsI( sPP, inP, lP )        /* parse merge bit field */
  647. char        **sPP;        /* pointer to return string */
  648. INPUT        *inP;        /* input control block */
  649. long        *lP;        /* result pointer */
  650. {
  651.     char    *wsP;        /* work string pointer */
  652.     char    *psP;        /* pre-token string pointer */
  653.     FAST long     wL;        /* "merge" bits */
  654.     FAST long     vL;        /* temp to convert literal tables */
  655.     FAST int     rcI;        /* return code */
  656.     FAST int     lcI;        /* last character */
  657.     FAST LIT    *litP;        /* literal pointer */
  658.  
  659.     vL = 0;
  660.     wsP = psP = *sPP;                    /* buffer pointer */
  661.     lcI = 0;
  662.     for(;;) {
  663.     rcI = NextToke( &wsP, "|,", (int *)0 ) ;    /* next token */
  664.     switch( rcI ) {
  665.     case TOKE_EOL:
  666.     case TOKE_TRM:
  667.         if ( lcI == 0 && CV_TokeLong != '|' )
  668.         goto Good;
  669.     case TOKE_STR:
  670.         goto Error;
  671.  
  672.     case TOKE_LIT:
  673.         if ( (litP = SearchLitTableP( &CV_TokeToke[1], inP->ILitTabP )) == (LIT *)0 )
  674.         goto Error;
  675.         wL = litP->LValueD;
  676.         vL |= wL;
  677.         break;
  678.  
  679.     case TOKE_FLT:            /* float */
  680.     case TOKE_DBL:            /* double */
  681.         wL = (CV_TokeDBL < 0.0? (CV_TokeDBL-0.5):(CV_TokeDBL+0.5));
  682.         goto IntCom;
  683.     case TOKE_CHR:            /* quoted character */
  684.     case TOKE_INT:            /* integer */
  685.         wL = CV_TokeLong;
  686.         IntCom:
  687.         if ( (inP->IInFuncC & IO_LITONLY) != 0 )
  688.         goto Error;
  689.         vL |= wL;            /* merge in new bits */
  690.         break;
  691.  
  692.     }
  693.     psP = wsP;
  694.     if ( *wsP == '|' ) {        /* valid data, see if more */
  695.          wsP++;
  696.          lcI = '|';
  697.     } else lcI = 0;
  698.     }
  699.  
  700. Good:
  701.     *lP  = vL;
  702.     *sPP = wsP;
  703.     return( 0 );
  704.  
  705. Error:
  706.     *sPP = psP;
  707.     return( -1 );
  708. }
  709. /*   */
  710. /************************************************************************
  711.  *                                    *
  712.  *    ParseStrI() - Parse a string or file name            *
  713.  *                                    *
  714.  ************************************************************************
  715.      Only looks for one of them.  If the string or file name
  716.      decodes like a valid floating point number or double,
  717.      this is an error.
  718.  */
  719.  
  720. LOCAL int ParseStrI( sPP, inP, SCI, InMI )    /* parse a string or file name */
  721. char        **sPP;        /* pointer to buffer pointer */
  722. INPUT        *inP;        /* input data block */
  723. int         SCI;        /* =1, syntax check */
  724. int         InMI;        /* in mode: IO_FNM, IO_FLD, IO_DTE or IO_STR */
  725. {
  726.     char    *wsP;        /* work string pointer */
  727.     FAST char    *asP;        /* work string pointer */
  728.     FAST char    *cP;        /* data pointer */
  729.     FAST char    *sP;        /* string pointer */
  730.     FAST int     lenI;        /* length of string (max) */
  731.     FAST int     rcI;        /* internal return code */
  732.     FAST int     cI;        /* character */
  733.  
  734.     if ( inP == (INPUT *)0 || (cP = inP->IValP) == (char *)0 )
  735.     return( 0 );            /* bad data pointer */
  736.  
  737.     if ( sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
  738.     return( 0 );            /* bad buffer pointer */
  739.  
  740.     lenI = inP->ISizeI & 0xff;        /* size of string */
  741.     rcI  = NextToke( &wsP, ",", (int *)0 );
  742.     switch( rcI ) {
  743.     case TOKE_EOL:
  744.     case TOKE_TRM:
  745.     if ( (inP->IInFuncC & IO_OPT) == 0 )
  746.         goto Error;    
  747.     if ( CV_TokeLong == ',' )    /* skip this one */
  748.         wsP++;            /* skip the terminal too */
  749.     break;
  750.  
  751.     case TOKE_FLT:
  752.     case TOKE_DBL:
  753.     case TOKE_INT:
  754.     default:
  755.     goto Error;
  756.  
  757.     case TOKE_CHR:            /* quoted character */
  758.     if ( InMI == IO_FNM || InMI == IO_FLD || InMI == IO_DTE )
  759.         goto Error;            /* invalid file */
  760.     if ( !SCI ) {
  761.         *cP++ = CV_TokeLong;
  762.         *cP++ = 0;
  763.     }
  764.     goto GotVal;
  765.  
  766.     case TOKE_LIT: sP = &CV_TokeToke[1];   goto TokeStore;
  767.     case TOKE_STR: sP = &CV_TokeString[1];
  768.     TokeStore:
  769.     switch( InMI ) {
  770.     case IO_FNM:    /* --- File name, do minimal syntax check --- */
  771.         for( asP = sP; (cI = *asP) != 0; asP++ ) {
  772.         if ( !( ('0' <= cI && cI <= '9') ||
  773.                 ('a' <= cI && cI <= 'z') ||
  774.                 ('A' <= cI && cI <= 'Z') ||
  775.              '.' == cI || '_' == cI || ':' == cI ||
  776.              '/' == cI || '\\' == cI ) )
  777.             goto Error;        /* invalid file name */
  778.         }
  779.         break;
  780.  
  781.     case IO_FLD:    /* --- Field reference, do syntax check --- */
  782.         rcI = 0;        /* state variable */
  783.         for( asP = sP; (cI = *asP) != 0; asP++ ) {
  784.         switch( cI ) {
  785.         case '.':    /* field-label separator */
  786.             if ( rcI || asP == sP ) goto Error;
  787.             rcI = 1;
  788.             break;
  789.  
  790.         case '(':
  791.         case '[':    /* start of offset */
  792.             if ( rcI >= 2 ) goto Error;
  793.             rcI = 2;
  794.             if ( asP[1] == '+' | asP[1] == '-' ) asP++;
  795.             break;
  796.  
  797.         case '0': case '1': case '2': case '3': case '4':
  798.         case '5': case '6': case '7': case '8': case '9':
  799.             if ( rcI == 2 ) rcI = 3;
  800.             if ( rcI > 3 ) goto Error;
  801.             break;
  802.  
  803.         case ')':
  804.         case ']':    /* end of offset */
  805.             if ( rcI < 3 ) goto Error;
  806.             rcI = 4;
  807.             break;
  808.  
  809.         default:
  810.             if ( rcI > 1 ) goto Error;
  811.             if ( !( ('a' <= cI && cI <= 'z') ||
  812.                 ('A' <= cI && cI <= 'Z') ||
  813.                 cI == '/' || cI == '_' ) )
  814.             goto Error;
  815.         }
  816.         }
  817.         break;
  818.  
  819.     case IO_DTE:        /* syntax check on date */
  820.         rcI = 0;
  821.         for( asP = sP; (cI = *asP) != 0; asP++ ) {
  822.         switch( cI ) {
  823.         case '-':    /* field separator */
  824.         case '/':
  825.             if ( rcI == 0 && asP == sP ) goto Error;
  826.             if ( asP[-1] == '-' || asP[-1] == '/' )
  827.             goto Error;
  828.             if ( rcI >= 2 ) goto Error;
  829.             rcI++;
  830.             break;
  831.  
  832.         case '0': case '1': case '2': case '3': case '4':
  833.         case '5': case '6': case '7': case '8': case '9':
  834.             break;
  835.  
  836.         default:
  837.             goto Error;
  838.         }
  839.         }
  840.         if ( rcI != 2 ) goto Error;
  841.         break;
  842.     }
  843.  
  844.     if ( !SCI ) {
  845.         strncpy( cP, sP, lenI );
  846.         cP[lenI-1] = 0;
  847.     }
  848.     GotVal:
  849.     ConvertedL++;
  850.     if ( *wsP == ',' )
  851.         wsP++;            /* skip separator */
  852.     break;
  853.     }
  854.  
  855.     *sPP = wsP;                /* position after token */
  856.     return( 0 );
  857.  
  858. Error:
  859.     return( -1 );
  860. }
  861. /*   */
  862. /************************************************************************
  863.  *                                    *
  864.  *    ParseValI() - Parse an integer, long, or float or array of them    *
  865.  *                                    *
  866.  ************************************************************************
  867.     Looks for: value,value,value
  868.         or: value value value, value
  869.        (accepts commas or spaces or mixed as delimiters)
  870.     value is:  'c'    - quoted character
  871.            int  - decimal, hex, octal, or binary integer
  872.            flt  - floating point number
  873.            lit  - literal with a numeric translation
  874.  */
  875.  
  876. LOCAL int ParseValI( sPP, inP, SCI )    /* parse an integer */
  877. char        **sPP;        /* pointer to char string */
  878. INPUT        *inP;        /* current command table entry */
  879. int         SCI;        /* =1, syntax check */
  880. {
  881.     char    *wsP;        /* work string pointer */
  882.     char    *psP;        /* pre-token position */
  883.     FAST int     rcI;        /* return code */
  884.     FAST int     vctrI;        /* variable counter */
  885.     FAST int     vctr0I;    /* initial variable counter */
  886.     FAST char    *cP;        /* data pointer */
  887.     FAST long     vL;        /* work long */
  888.     FAST double     vD;        /* work double */
  889.     FAST LIT    *litP;        /* literal table pointer */
  890.     FAST int     ValTypeI;    /* value type */
  891.     long     wL;        /* work long */
  892.  
  893.     if ( inP == (INPUT *)0 || (cP = inP->IValP) == (char *)0 )
  894.     return( 0 );            /* bad data pointer */
  895.  
  896.     if ( sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
  897.     return( 0 );            /* bad buffer pointer */
  898.  
  899.     vctr0I   = inP->IItemsI & 0xff;        /* # of items */
  900.     vctr0I   = (vctr0I < 1)? 1:vctr0I;        /* at least one item */
  901.     ValTypeI = (inP->IInFuncC & IO_MASK);    /* type of conversion */
  902.  
  903.     for( vctrI = vctr0I; vctrI > 0; vctrI--) {
  904.     psP = wsP;
  905.     rcI = NextToke( &wsP, ",", (int *)0 );
  906.     switch( rcI ) {
  907.     case TOKE_EOL:            /* EOL or terminal */
  908.     case TOKE_TRM:
  909.         if ( (inP->IInFuncC & IO_OPT) == 0 )
  910.         goto Error;        /* not optional */
  911.         if ( CV_TokeLong == ',' ) {
  912.         wsP++;            /* skip the terminal */
  913.         cP += inP->ISizeI&0xff;    /* skip this item */
  914.         break;
  915.         }
  916.         goto Good;            /* done with line */
  917.  
  918.     case TOKE_STR:            /* strings don't work */
  919.         goto Error;
  920.  
  921.     case TOKE_LIT:            /* look up literal in table */
  922.  
  923.         litP = SearchLitTableP( &CV_TokeToke[1], inP->ILitTabP );
  924.         if ( litP == (LIT *)0 ) {
  925.         /* --- if "IO_BIT", we may have a complex construct --- */
  926.         if ( ValTypeI == IO_BIT ) {
  927.             if ( ParseBitsI( &psP, inP, &wL ) != 0 )
  928.             goto Error;
  929.             vL = wL;        /* successful "bit-parse" */
  930.             vD = vL;
  931.         } else goto Error;
  932.         } else {
  933.         vD = litP->LValueD;
  934.         vL = vD;
  935.         }
  936.         goto StoreToke2;
  937.  
  938.     case TOKE_FLT:            /* float, make it long */
  939.     case TOKE_DBL:
  940.         vD = CV_TokeDBL;
  941.         vL = vD;
  942.         goto StoreToke;
  943.  
  944.     case TOKE_CHR:            /* char or int, use it */
  945.     case TOKE_INT:
  946.         vL = CV_TokeLong;
  947.         vD = vL;
  948.     StoreToke:
  949.         if ( ValTypeI != IO_FLT ) {
  950.         /* --- round integers --- */
  951.         vL = (vD < 0.0? (vD - 0.5):(vD + 0.5));
  952.         vD = vL;        /* store as integer */
  953.         }
  954.         if ( (inP->IInFuncC & IO_LITONLY) != 0 &&
  955.          (litP = inP->ILitTabP) != (LIT *)0 ) {
  956.         /* --- Check to see it is in literal table --- */
  957.         for( ; litP->LNameCP != (char *)0; litP++ ) 
  958.             if ( vD == litP->LValueD )
  959.             goto StoreToke2; /* found in table, store it */
  960.         goto Error;         /* not in table ! */
  961.         }
  962.          
  963.     StoreToke2:            /* passed literal test */
  964.         ConvertedL++;
  965.         if ( !SCI )            /* syntax check only */
  966.         StoreValueI( cP, inP, vD );
  967.         cP += inP->ISizeI & 0xff;
  968.  
  969.         if ( *wsP == ',' )
  970.         wsP++;            /* skip optional comma */
  971.         break;
  972.     }
  973.     }
  974.  
  975. Good:
  976.     *sPP = wsP;                /* position after token */
  977.     return( 0 );
  978.  
  979. Error:
  980.     *sPP = psP;                /* position prior to error */
  981.     return( -1 );
  982. }
  983. /*   */
  984. /************************************************************************
  985.  *                                    *
  986.  *    ParseLstI() - Parse an assignment list                *
  987.  *                                    *
  988.  ************************************************************************
  989.     This routine takes a list of variables to parse and
  990.     parses each of them in turn until the end of list is reached.
  991.     When using commas, a value can be left alone by a "double" comma.
  992.  
  993.     inP->IValP    points to the list of input items
  994.           The last item has a null data pointer
  995.  */
  996.  
  997. LOCAL int ParseLstI( sPP, inP, SCI )        /* parse a command list */
  998. char        **sPP;        /* pointer to buffer pointer */
  999. INPUT        *inP;        /* input list pointer */
  1000. int         SCI;        /* =1, syntax check only */
  1001. {
  1002.     FAST INPUT    *ainP;        /* alternate input list */
  1003.     char    *wsP;        /* work character pointer */
  1004.     FAST int     rcI;        /* local return code */
  1005.     FAST int     wtI;        /* work type */
  1006.  
  1007.     if ( inP == (INPUT *)0 || (ainP = (INPUT *)inP->IValP) == (INPUT *)0 )
  1008.     return( -1 );        /* bad call */
  1009.  
  1010.     if ( sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
  1011.     return( 0 );            /* bad buffer pointer */
  1012.  
  1013.     rcI = 0;
  1014.     for( ; ainP->IValP != (char *)0; ainP++ ) {
  1015.  
  1016.     /* --- Parse the following values as required --- */
  1017.  
  1018.     switch( (wtI = ainP->IInFuncC & IO_MASK) ) {
  1019.     case IO_NAK: default:      rcI = 0;                   break;
  1020.     case IO_BIT:
  1021.     case IO_INT: case IO_FLT: rcI = ParseValI( &wsP, ainP, SCI );       break;
  1022.     case IO_STR: case IO_FNM:
  1023.     case IO_DTE: case IO_FLD: rcI = ParseStrI( &wsP, ainP, SCI, wtI ); break;
  1024.     case IO_LST:          rcI = ParseLstI( &wsP, ainP, SCI );       break;
  1025.     }
  1026.  
  1027.     if ( rcI < 0 )
  1028.         break;
  1029.     }
  1030.  
  1031.     *sPP = wsP;
  1032.     return( rcI );
  1033. }
  1034. /*   */
  1035. /************************************************************************
  1036.  *                                    *
  1037.  *    ParseLineI() - Parse a Line & perform any tasks required    *
  1038.  *                                    *
  1039.  ************************************************************************
  1040.     rc = -1, error in parsing
  1041.     rc =  0, all is well, nothing to do
  1042.     rc =  1, executed successfully
  1043.  
  1044.     Procedure:
  1045.     1) Parse the input string & get a literal token.
  1046.     2) Search the command table for the literal.
  1047.        - Not found: error
  1048.     3) Execute the "input routine" if any.
  1049.        - rc <> 0, error
  1050.     4) Check for "eol"
  1051.        - not there, error.
  1052.     5) Execute the "action routine" if any.
  1053.        - rc <> 0, error
  1054.     6) done.
  1055.  */
  1056.  
  1057. int ParseLineI( sPP, CmdTabP, ErrFP, SCI )    /* parse a line */
  1058. char        **sPP;        /* character string pointer */
  1059. CMD        *CmdTabP;    /* command table */
  1060. FILE        *ErrFP;        /* file handle for errors */
  1061. int         SCI;        /* =1, perform syntax check only */
  1062. {
  1063.     char    *wsP;        /* work string pointer */
  1064.     FAST char    *asP;        /* alt string pointer */
  1065.     FAST int     rcI;        /* work return code */
  1066.     FAST int     wtI;        /* work type */
  1067.     FAST CMD    *cmdP;        /* work command pointer */
  1068.     FAST INPUT    *inP;        /* i/o block pointer */
  1069.     FAST int     HelpI;        /* user needs help in terms of commands */
  1070.     FAST char    *PrefixP;    /* prefix */
  1071.     char     buf[80];    /* message buffer */
  1072.  
  1073.     if ( CmdTabP == (CMD *)0 ||
  1074.      sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
  1075.     goto Ok;            /* nothing to do */
  1076.  
  1077.     if ( ErrFP == (FILE *)0 )
  1078.     ErrFP = stderr;
  1079.  
  1080.     /* --- Check to see if we are reading "lotus" format --- */
  1081.  
  1082.     if ( *wsP == '"' ) {
  1083.     /* --- Lotus format line, "fix" it up --- */
  1084.     asP = wsP;
  1085.     *asP++ = ' ';                /* replace leading quote */
  1086.     if ( strncmp( asP, "PARM", 4 ) == 0 ) {
  1087.         *--asP = '!';            /* make it a "comment" line */
  1088.         goto Ok;                /* nothing to do ! */
  1089.     }
  1090.     while( *asP && *asP != '"' ) asP++;
  1091.     if ( *asP ) {
  1092.         *asP++ = ' ' ;            /* kill trailing quote */
  1093.         if ( *asP == ',' ) *asP++ = ' ';    /* comma */
  1094.         if ( *asP == '"' ) *asP++ = ' ';    /* next quote */
  1095.         while( *asP && *asP != '"' ) asP++;
  1096.         if ( *asP ) {
  1097.         *asP++ = ' ';                /* kill final quote */
  1098.         if ( *asP == ',' ) *asP++ = ' ';    /* comma */
  1099.         if ( *asP == '"' ) *asP++ = ' ';    /* next quote */
  1100.         }
  1101.     }
  1102.     }
  1103.  
  1104.     /* --- Find the command in the command table --- */
  1105.  
  1106.     PrefixP = (ErrFP == stdout? "":"=P= ");
  1107.     asP = wsP;                    /* save for syntax error */
  1108.     HelpI = 0;
  1109.     rcI = NextToke( &wsP, "=?", (int *)0 );     /* get next token */
  1110.     if ( *wsP == '?' ) HelpI = 1;
  1111.     switch( rcI ) {
  1112.     case TOKE_TRM:
  1113.     if ( CV_TokeLong == '=' ) goto Syntax;
  1114.     asP = wsP;
  1115.     if ( HelpI ) {
  1116.         wsP++;
  1117.         asP = wsP;
  1118.         rcI = NextToke( &wsP, "?", (int *)0 ); /* get next token */
  1119.         switch( rcI ) {
  1120.         case TOKE_EOL: case TOKE_TRM:
  1121.         if ( CV_TokeLong == '?' )
  1122.             PrintTableI( CmdTabP, ErrFP, PrefixP, -1 );
  1123.         else    PrintTableI( CmdTabP, ErrFP, PrefixP,  0 );
  1124.         break;
  1125.  
  1126.         case TOKE_LIT:
  1127.         if ( (cmdP = SearchCmdTableP( &CV_TokeToke[1], CmdTabP, 0 )) != (CMD *)0 ) {
  1128.             /* --- Single unique item --- */
  1129.             PrintTableItemI( cmdP, ErrFP, PrefixP, 0 );
  1130.             break;
  1131.         }
  1132.         for( wtI = 0, cmdP = CmdTabP; ; cmdP++ ) {
  1133.             /* --- ambiguous item --- */
  1134.             if ( (cmdP = SearchCmdTableP( &CV_TokeToke[1], cmdP, 1)) == (CMD *)0 )
  1135.             break;
  1136.             wtI++;
  1137.             PrintTableItemI( cmdP, ErrFP, PrefixP, 0 );
  1138.         }
  1139.         if ( wtI == 0 ) goto Syntax;
  1140.         default:
  1141.         break;
  1142.         }
  1143.         rcI = -1;
  1144.         goto Exit;
  1145.     }
  1146.     case TOKE_EOL:
  1147.     goto Ok;            /* nothing to do */
  1148.  
  1149.     case TOKE_LIT: break;        /* command to process */
  1150.     default: goto Syntax;        /* error */
  1151.     }
  1152.  
  1153.     /* --- If help is requested, print out all "ambiguous" commands --- */
  1154.  
  1155.     cmdP = SearchCmdTableP( &CV_TokeToke[1], CmdTabP, 0 );
  1156.     if ( HelpI ) {
  1157.     if ( cmdP ) {        /* print out options associated with this command */
  1158.         PrintTableItemI( cmdP, ErrFP, (char *)0, -1 );
  1159.     } else {        /* print out commands which match */
  1160.         for( wtI = 0, cmdP = CmdTabP; ; cmdP++ ) {
  1161.         if ( (cmdP = SearchCmdTableP( &CV_TokeToke[1], cmdP, 1)) == (CMD *)0 )
  1162.             break;
  1163.         wtI++;
  1164.         fprintf( ErrFP, "%s%s\n", PrefixP, cmdP->CNameCP );
  1165.         }
  1166.         if ( wtI == 0 ) goto Syntax;
  1167.     }
  1168.     fflush( ErrFP );
  1169.     rcI = -1;
  1170.     goto Exit;
  1171.     }
  1172.  
  1173.     /* --- Search Command Table for match --- */
  1174.  
  1175.     if ( cmdP == (CMD *)0 ) {
  1176.     wsP = asP;            /* point to token */
  1177.     goto Syntax;
  1178.     }
  1179.     if ( (!cmdP->CActRtnP || (cmdP->CInS.IInFuncC & IO_DSP) != 0 )
  1180.       && *wsP == '=' ) {
  1181.     /* --- assignment statement, kill optional "=" sign --- */
  1182.     wsP++;
  1183.     while( *wsP && *wsP <= ' ' ) wsP++;
  1184.     }
  1185.  
  1186.     /* --- Parse variables as required --- */
  1187.  
  1188.     ConvertedL = 0;            /* nothing converted yet */
  1189.     inP = &cmdP->CInS;
  1190.     switch( (wtI = inP->IInFuncC & IO_MASK) ) {
  1191.     case IO_NAK: default:    rcI = 0;                break;
  1192.     case IO_BIT:
  1193.     case IO_INT: case IO_FLT:    rcI = ParseValI( &wsP, inP, SCI );      break;
  1194.     case IO_STR: case IO_FNM:    
  1195.     case IO_DTE: case IO_FLD:    rcI = ParseStrI( &wsP, inP, SCI, wtI ); break;
  1196.     case IO_LST:        rcI = ParseLstI( &wsP, inP, SCI );      break;
  1197.     }
  1198.     if ( rcI != 0 ) goto Syntax;
  1199.  
  1200.     /* --- Check for end of line --- */
  1201.  
  1202.     if ( *wsP != COMMENT && *wsP != '\0' )
  1203.     goto Syntax;
  1204.  
  1205.     /* --- Perform any "post" action routine required --- */
  1206.  
  1207.     if ( cmdP->CActRtnP ) {
  1208.     if ( SCI )    rcI = 0;
  1209.     else        rcI = (cmdP->CActRtnP)( cmdP, ConvertedL, ErrFP );
  1210.     if ( rcI != 0 ) {
  1211.         sprintf( buf, "Action routine for command <%s> failed rc=%d\n",
  1212.         cmdP->CNameCP, rcI );
  1213.         MsgER( buf );
  1214.         goto Exit;
  1215.     }
  1216.     } else if ( ConvertedL == 0 ) {
  1217.     /* --- Assignment MUST have a converted item --- */
  1218.     goto Syntax;
  1219.     }
  1220.  
  1221. Exit:
  1222. #ifdef TESTCMD
  1223.     printf( "rcI = %d, ConvertedL = %ld\n", rcI, ConvertedL );
  1224. #endif
  1225.     *sPP = wsP;
  1226.     return( rcI );
  1227.  
  1228. Ok:
  1229.     rcI = 0;
  1230.     goto Exit;
  1231.  
  1232. Syntax:
  1233.  
  1234.     /* --- Clean up the string --- */
  1235.  
  1236.     for( asP = *sPP; *asP != 0; asP++ ) {
  1237.     if ( *asP == '\r' || *asP == '\n' ) *asP = 0;
  1238.     else if ( *asP < ' ' ) *asP = ' ';
  1239.     }
  1240.  
  1241.     /* --- Put a ^ under where the error occurred --- */
  1242.  
  1243.     fputs( *sPP, ErrFP );    /* write the line */
  1244.     fputs( "\n", ErrFP );
  1245.     for( asP = *sPP; asP < wsP; asP++ )
  1246.     fputs( " ", ErrFP );    /* space over */
  1247.     fputs( "^ Syntax Error\n", ErrFP );    /* show where error is */
  1248.     return( -1 );
  1249. }
  1250. /*   */
  1251. /************************************************************************
  1252.  *                                    *
  1253.  *    PrintBitI() - Expand out & print a bit-field            *
  1254.  *                                    *
  1255.  ************************************************************************
  1256.     NOTE: This routine should be called ONLY WHEN:
  1257.     1) a literal table exists.
  1258.     2) the value to decode is NON-zero
  1259.     3) the data format is IO_BIT.
  1260.  */
  1261.  
  1262. static char *FmtA[] =    /* formats */
  1263. { "%ld", "%lu", "0x%lx", "0%lo", "%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f" };
  1264.  
  1265. LOCAL int PrintBitI( vL, inP, OutFP )    /* expand & print a bit-field */
  1266. FAST long     vL;        /* value to expand */
  1267. FAST INPUT    *inP;        /* literal table pointer */
  1268. FAST FILE    *OutFP;        /* output file pointer */
  1269. {
  1270.     FAST LIT    *litP;        /* literal pointer */
  1271.     FAST long     wL;        /* work long */
  1272.  
  1273.     litP = inP->ILitTabP;
  1274.     for( ; litP->LNameCP != 0; litP++ ) {
  1275.     if ( (wL = litP->LValueD) != 0 ) {
  1276.         if ( (vL & wL) == wL ) {
  1277.         fputs( litP->LNameCP, OutFP );
  1278.         vL &= ~wL;
  1279.         if ( vL == 0 ) break;
  1280.         fputs( "|", OutFP );
  1281.         }
  1282.     }
  1283.     }
  1284.  
  1285.     if ( vL != 0 )
  1286.     fprintf( OutFP, FmtA[inP->IOutFuncC], vL );
  1287.  
  1288.     return( 0 );
  1289. }
  1290. /*   */
  1291. /************************************************************************
  1292.  *                                    *
  1293.  *    PrintValI() - Print out a data value                *
  1294.  *                                    *
  1295.  ************************************************************************
  1296.  */
  1297.  
  1298. LOCAL int PrintValI( inP, OutFP, IPI )    /* print out a data value */
  1299. FAST INPUT    *inP;        /* input list pointer */
  1300. FAST FILE    *OutFP;        /* output file pointer */
  1301. FAST int     IPI;        /* =1, lotus import format */
  1302. {
  1303.     FAST UVP     p;        /* universal pointer */
  1304.     FAST long     vL;        /* long value */
  1305.     FAST long     UsgnL;        /* "unsigned mask" */
  1306.     FAST long     SBitL;        /* sign bit */
  1307.     FAST double     vD;        /* double value */
  1308.     FAST int     ctrI;        /* work counter */
  1309.     FAST int     wxI;        /* work index */
  1310.     FAST LIT    *litP;        /* literal table pointer */
  1311.     FAST int     lIPI;        /* local IPI */
  1312.     FAST int     ValTypeI;    /* value type */
  1313.     FAST int     exI;        /* end index */
  1314.     FAST int     typeI;        /* type index */
  1315.     FAST char    *sP;        /* string pointer */
  1316.  
  1317.     if ( inP == (INPUT *)0 || (p.cP = inP->IValP) == (char *)0 )
  1318.     return( 0 );
  1319.  
  1320.     if ( OutFP == (FILE *)0 )
  1321.     OutFP = stdout;
  1322.  
  1323.     ctrI = inP->IItemsI & 0xff;
  1324.     ctrI = (ctrI < 1? 1:ctrI);
  1325.     if ( IPI < 0 ) {
  1326.     /* --- Print out syntax for this item --- */
  1327.     exI   = inP->IInFuncC;
  1328.     typeI = exI & IO_MASK;
  1329.     litP  = inP->ILitTabP;
  1330.     if ( ConvertedL )            fputs( ",",     OutFP );
  1331.     ConvertedL++;
  1332.     if ( (exI & IO_OPT) != 0 )        fputs( "[",      OutFP );
  1333.     if (      typeI == IO_STR )        fputs( "STRING", OutFP );
  1334.     else if ( typeI == IO_FNM )        fputs( "FILE",   OutFP );
  1335.     else if ( typeI == IO_FLD )        fputs( "REF.LAB[+/-OFF]", OutFP );
  1336.     else if ( typeI == IO_DTE )        fputs( "MM/DD/YY", OutFP );
  1337.     else {
  1338.         if ( ctrI > 1 )             fputs( "LIST:", OutFP );
  1339.         if ( inP->ILitTabP != (LIT *)0 )    fputs( "{", OutFP );
  1340.         wxI = 0;
  1341.         if ( (exI & IO_LITONLY) == 0 || litP == (LIT *)0 ) {
  1342.         switch( typeI ) {
  1343.         default:    sP = "?";    break;
  1344.         case IO_INT:    sP = "INT";    break;
  1345.         case IO_BIT:    sP = "BIT";    break;
  1346.         case IO_FLT:    sP = "REAL";    break;
  1347.         }
  1348.         fputs( sP, OutFP );
  1349.         wxI = 1;
  1350.         }
  1351.         if ( litP != (LIT *)0 ) {
  1352.         sP = (typeI == IO_BIT? "|":",");
  1353.         for( ; litP->LNameCP != (char *)0; litP++ ) {
  1354.             if ( wxI ) fputs( sP, OutFP );
  1355.             wxI++;
  1356.             fputs( litP->LNameCP, OutFP );
  1357.         }
  1358.         fputs( "}", OutFP );
  1359.         }
  1360.     }
  1361.     if ( (exI & IO_OPT) != 0 )        fputs( "]",      OutFP );
  1362.  
  1363.     return( 0 );
  1364.     }
  1365.  
  1366.     lIPI = IPI;
  1367.     if ( IPI != 0 && ctrI > 1 ) {
  1368.     lIPI = 0;
  1369.     fputs( ",\"", OutFP );
  1370.     ConvertedL = 0;
  1371.     }
  1372.  
  1373.     if ( IPI >= 0 && ctrI > 1 ) {
  1374.     /* --- Omit trailing items in an array which migh be zero --- */
  1375.     typeI = 0;
  1376.     switch( (inP->IInFuncC & IO_MASK) ) {
  1377.     case IO_INT:
  1378.     case IO_BIT:
  1379.         switch( inP->ISizeI & 0xff ) {
  1380.         case sizeof(char):    typeI = 1;    break;
  1381.         case sizeof(short):    typeI = 2;    break;
  1382.         case sizeof(long):    typeI = 3;    break;
  1383.         }
  1384.         break;
  1385.     case IO_FLT:
  1386.         if ( (inP->ISizeI & 0xff) == sizeof(float) )
  1387.          typeI = 4;
  1388.         else typeI = 5;
  1389.         break;
  1390.     }
  1391.     exI = 0;
  1392.     if ( typeI != 0 ) {
  1393.         for( wxI = 0; wxI < ctrI; wxI++ ) {
  1394.         switch( typeI ) {
  1395.         case 1:    if ( *p.cP++ != 0  ) exI = wxI; break;
  1396.         case 2: if ( *p.sP++ != 0  ) exI = wxI; break;
  1397.         case 3: if ( *p.lP++ != 0  ) exI = wxI; break;
  1398.         case 4: if ( *p.fP++ != 0. ) exI = wxI; break;
  1399.         case 5: if ( *p.dP++ != 0. ) exI = wxI; break;
  1400.         }
  1401.         }
  1402.         exI++;
  1403.         if ( ctrI > exI && IPI > 0 ) 
  1404.         exI++;
  1405.         ctrI = exI;            /* re-set end point */
  1406.     }
  1407.     p.cP = inP->IValP;        /* restore pointer */
  1408.     }
  1409.  
  1410.     for( ; --ctrI >= 0; ) {
  1411.     wxI = 0;
  1412.     switch( (ValTypeI = inP->IInFuncC & IO_MASK) ) {
  1413.     case IO_NAK: case IO_LST: default:
  1414.         break;
  1415.     case IO_BIT:
  1416.     case IO_INT:
  1417.         switch( (inP->ISizeI & 0xff) ) {
  1418.         case sizeof(char):
  1419.         UsgnL = 0x000000ffL; SBitL = 0x00000080L;
  1420.         vL = *p.cP++; break;
  1421.         case sizeof(short):
  1422.         UsgnL = 0x0000ffffL; SBitL = 0x00008000L;
  1423.         vL = *p.sP++; break;
  1424.         case sizeof(long):
  1425.         UsgnL = 0xffffffffL; SBitL = 0x00000000L;
  1426.         vL = *p.lP++; break;
  1427.         default:
  1428.         UsgnL = 0xffffffffL; SBitL = 0x00000000L;
  1429.         vL = *p.iP++; break;
  1430.         }
  1431.         if ( inP->IOutFuncC == FMT_INTS ) {
  1432.         if ( (vL & SBitL) != 0 ) vL |= ~UsgnL;
  1433.         } else {
  1434.         vL &= UsgnL;
  1435.         }
  1436.  
  1437.         /* --- See if it is in a literal table & use literal --- */
  1438.         
  1439.         if ( ConvertedL ) fputs( ",", OutFP );
  1440.         ConvertedL++;
  1441.         if ( vL != 0 && ValTypeI == IO_BIT &&
  1442.          (litP = inP->ILitTabP) != (LIT *)0 ) {
  1443.         /* --- Translated an "or'd" bit-field --- */
  1444.         if ( lIPI ) fputs( "\"", OutFP );
  1445.         PrintBitI( vL, inP, OutFP );
  1446.         if ( lIPI ) fputs( "\"", OutFP );
  1447.         break;
  1448.         }
  1449.  
  1450.         if ( (litP = inP->ILitTabP) != (LIT *)0 ) {
  1451.         vD = vL;    /* map to double for compare */
  1452.         wxI = 0;    /* flag for "translated" */
  1453.         for( ; litP->LNameCP != (char *)0; litP++ ) {
  1454.             if ( vD == litP->LValueD ) {
  1455.             wxI++;
  1456.             if ( lIPI ) fputs( "\"", OutFP );
  1457.             fputs( litP->LNameCP, OutFP );
  1458.             if ( lIPI ) fputs( "\"", OutFP );
  1459.             break;
  1460.             }
  1461.         }
  1462.         if ( wxI ) break;
  1463.         }
  1464.         fprintf( OutFP, vL==0?"0":FmtA[inP->IOutFuncC], vL );
  1465.         break;
  1466.  
  1467.     case IO_FLT:
  1468.         if ( (inP->ISizeI & 0xff) == sizeof(float) ) {
  1469.         vD = *p.fP++;
  1470.         } else {
  1471.         vD = *p.dP++;
  1472.         }
  1473.         if ( ConvertedL ) fputs( ",", OutFP );
  1474.         ConvertedL++;
  1475.         if ( (litP = inP->ILitTabP) != (LIT *)0 ) {
  1476.         wxI = 0;
  1477.         for( ; litP->LNameCP != (char *)0; litP++ ) {
  1478.             if ( vD == litP->LValueD ) {
  1479.             wxI++;
  1480.             if ( lIPI ) fputs( "\"", OutFP );
  1481.             fputs( litP->LNameCP, OutFP );
  1482.             if ( lIPI ) fputs( "\"", OutFP );
  1483.             break;
  1484.             }
  1485.         }
  1486.         if ( wxI ) break;
  1487.         }
  1488.         fprintf( OutFP, vD==0.0?"0":FmtA[inP->IOutFuncC], vD );
  1489.         break;
  1490.  
  1491.     case IO_STR:
  1492.         wxI = 1;
  1493.         goto StrCom;
  1494.     case IO_FNM:
  1495.     case IO_FLD:
  1496.     case IO_DTE:
  1497.         if ( lIPI ) wxI = 1;
  1498.     StrCom:
  1499.         if ( ConvertedL )    fputs( ",", OutFP );
  1500.         if ( wxI )        fputs( "\"", OutFP );
  1501.         fputs( p.cP, OutFP );
  1502.         if ( wxI )        fputs( "\"", OutFP );
  1503.         ConvertedL++;
  1504.         goto Done;        /* --- lists of strings not allowed --- */
  1505.     }
  1506.     }
  1507.     if ( IPI != 0 && lIPI == 0 )
  1508.     fputs( "\"", OutFP );
  1509.  
  1510. Done:
  1511. #ifdef TESTCMD
  1512.     fflush( OutFP );
  1513. #endif
  1514.     return( 0 );
  1515. }
  1516. /*   */
  1517. /************************************************************************
  1518.  *                                    *
  1519.  *    PrintLstI() - Print out data values in a list            *
  1520.  *                                    *
  1521.  ************************************************************************
  1522.      inP->IValP has pointer to list of input items.
  1523.      Last item has a null data pointer
  1524.  */
  1525.  
  1526. LOCAL int PrintLstI( inP, OutFP, IPI )    /* print out a list of values */
  1527. INPUT        *inP;        /* input list pointer */
  1528. FILE        *OutFP;        /* output file pointer */
  1529. int         IPI;        /* =1, import format */
  1530. {
  1531.     INPUT    *ainP;        /* alternate input list */
  1532.     char    *wsP;        /* work character pointer */
  1533.     int         rcI;        /* local return code */
  1534.  
  1535.     if ( inP == (INPUT *)0 || (ainP = (INPUT *)inP->IValP) == (INPUT *)0 )
  1536.     return( -1 );        /* bad call */
  1537.  
  1538.     if ( OutFP == (FILE *)0 ) OutFP = stdout;
  1539.  
  1540.     if ( IPI>0 ) {
  1541.     fputs( ",\"", OutFP );
  1542.     ConvertedL = 0;
  1543.     }
  1544.     for( ; ainP->IValP != (char *)0; ainP++ ) {
  1545.     switch( (ainP->IInFuncC & IO_MASK) ) {
  1546.     case IO_NAK: default: break;
  1547.     case IO_LST:
  1548.         PrintLstI( ainP, OutFP, IPI<=0?IPI:0 );    break;
  1549.     case IO_BIT:
  1550.     case IO_INT: case IO_FLT:
  1551.     case IO_STR: case IO_FNM: case IO_DTE: case IO_FLD:
  1552.         PrintValI( ainP, OutFP, IPI<=0?IPI:0 );    break;
  1553.     }
  1554.     }
  1555.     if ( IPI>0 )
  1556.     fputs( "\"", OutFP );
  1557.  
  1558. #ifdef TESTCMD
  1559.     fflush( OutFP );
  1560. #endif
  1561.     return( 0 );
  1562. }
  1563. /*   */
  1564. /************************************************************************
  1565.  *                                    *
  1566.  *    PrintTableI() - Print out data values in table            *
  1567.  *                                    *
  1568.  ************************************************************************
  1569.      IPI Modes:
  1570.          -1, syntax structure
  1571.           0, variables for display
  1572.           1, variables for import
  1573.  */
  1574.  
  1575. LOCAL int PrintTableItemI( cmdP, OutFP, prefixCP, IPI )    /* print out table item */
  1576. CMD        *cmdP;        /* command table */
  1577. FILE        *OutFP;        /* output file pointer */
  1578. char        *prefixCP;    /* prefix for each line */
  1579. int         IPI;        /* =1, import format flag */
  1580. {
  1581.     INPUT    *inP;        /* input pointer */
  1582.     long     fposL;        /* file position */
  1583.     long     msgL;        /* message id */
  1584.     char    *msgP;        /* message pointer */
  1585.  
  1586.     if ( OutFP == (FILE *)0 )
  1587.     OutFP = stdout;
  1588.  
  1589.     if ( cmdP->CNameCP != (char *)0 ) {
  1590.     inP = &cmdP->CInS;        /* input block */
  1591.     if (   IPI >= 0 &&
  1592.          ( (cmdP->CActRtnP && (inP->IInFuncC & IO_DSP) == 0)
  1593.            || (inP->IInFuncC & IO_MASK) == IO_NAK) )
  1594.         return( 0 );        /* skip commands */
  1595.     fposL = ftell( OutFP );        /* save file position */
  1596.     if ( IPI <= 0 && prefixCP != (char *)0 && *prefixCP != 0 )
  1597.         fprintf( OutFP, "%s ", prefixCP );
  1598.     fprintf( OutFP, IPI>0?"\"%s\"":"%-20s ", cmdP->CNameCP );
  1599.  
  1600.     ConvertedL = IPI>0?1:0;
  1601.     switch( (inP->IInFuncC & IO_MASK) ) {
  1602.     case IO_NAK: default:        /* should not happen */
  1603.         break;
  1604.     case IO_BIT:
  1605.     case IO_INT: case IO_FLT:
  1606.     case IO_STR: case IO_FNM: case IO_DTE: case IO_FLD:
  1607.         PrintValI( inP, OutFP, IPI ); break;
  1608.     case IO_LST:
  1609.         PrintLstI( inP, OutFP, IPI ); break;
  1610.     }
  1611.     if ( (msgP = cmdP->CHelpCP) != (char *)0 ) {
  1612.         fposL = ftell( OutFP ) - fposL;
  1613.         if ( IPI <= 0 && fposL > 0 ) {
  1614.         fposL = (fposL & (-8));
  1615.         while( fposL < 40 ) {
  1616.             fputs( "\t", OutFP );
  1617.             fposL += 8;
  1618.         }
  1619.         }
  1620.         fprintf( OutFP, IPI>0?",\"!%s\"":"\t!%s", msgP );
  1621.     }
  1622.     fputs( "\n", OutFP );
  1623. #ifdef TESTCMD
  1624.     fflush( OutFP );
  1625. #endif
  1626.     }
  1627.  
  1628.     return( 0 );
  1629. }
  1630.  
  1631. int PrintTableI( cmdP, OutFP, prefixCP, IPI )    /* print out table */
  1632. CMD        *cmdP;        /* command table */
  1633. FILE        *OutFP;        /* output file pointer */
  1634. char        *prefixCP;    /* prefix for each line */
  1635. int         IPI;        /* =1, import format flag */
  1636. {
  1637.     INPUT    *inP;        /* input pointer */
  1638.     long     fposL;        /* file position */
  1639.  
  1640.     for(; cmdP->CNameCP != (char *)0; cmdP++ )
  1641.     PrintTableItemI( cmdP, OutFP, prefixCP, IPI );    /* print out table item */
  1642.  
  1643.     return( 0 );
  1644. }
  1645. /*   */
  1646. /************************************************************************
  1647.  *                                    *
  1648.  *    main() - Test Routine for Command Line Parser            *
  1649.  *                                    *
  1650.  ************************************************************************
  1651.  */
  1652.  
  1653. #ifdef TESTCMD
  1654.  
  1655. double    Tdouble    = {0};
  1656. float    Tfloat    = {0};
  1657. long    Tlong    = {0};
  1658. short    Tshort    = {0};
  1659. char    Tchar    = {0};
  1660. int    Tbool    = {0};
  1661. char    Tstr[]    = {"Test String for I/O"};
  1662. char    Tfil[]  = {"filenamegoeshere"};
  1663. char    Tfld[]    = {"field.label[offset]"};
  1664. char    TDate[] = {"mm/dd/yy"};
  1665. int    Bit1=0, Bit2=0;
  1666.  
  1667. short    Tarray[5] = {0,0,0,0,0};
  1668.  
  1669. LIT YesNo[] = {
  1670.  { "true",  1 }, { "yes", 1 }, { "on",  1 },
  1671.  { "false", 0 }, { "no",  0 }, { "off", 0 },
  1672.  { 0, 0 }
  1673. };
  1674.  
  1675. /* --- Input List to get several objects --- */
  1676.  
  1677. short    L1I, L2I, L3I;
  1678. long    L4I;
  1679.  
  1680. INPUT inl[] = {
  1681.   IVAL(L1I, IO_INT,        FMT_INTS, &YesNo[0]),
  1682.   IVAL(L2I, IO_INT|IO_OPT, FMT_INTS, &YesNo[0]),
  1683.   IVAL(L3I, IO_INT|IO_OPT, FMT_INTS, &YesNo[0]),
  1684.   IVAL(L4I, IO_INT,        FMT_INTS, &YesNo[0]),
  1685.   INUL
  1686. };
  1687.  
  1688. int actI = {0};
  1689.  
  1690. int ActionRtne( cmdP, cvL, ErrFP )
  1691. CMD        *cmdP;        /* command pointer associated with me */
  1692. long         cvL;        /* count routine */
  1693. FILE        *ErrFP;        /* error output file */
  1694. {
  1695.     fprintf( stdout, "actI = %d, Converted %ld items\n", actI, cvL );
  1696.     fflush( stdout );
  1697.     return( 0 );
  1698. }
  1699.  
  1700. int QuitI = {0};
  1701. int QuitRtne( cmdP, cvL, ErrFP )    /* quit command */
  1702. CMD        *cmdP;        /* command pointer associated with quit */
  1703. long         cvL;        /* # of conversions */
  1704. FILE        *ErrFP;        /* error output file */
  1705. { QuitI = 1; return( 0 ); }    /* set quit flag */
  1706.  
  1707. LIT Bits[] = {
  1708.   { "b1",  1 }, { "b2", 2 }, { "b3", 4 }, { "b4", 8 }, {0} };
  1709. CMD cmds[] = {
  1710.  { "quit",    "quit help", QuitRtne, INUL },
  1711.  { "list",    "list help", 0, ILIST( inl, 0 ) },
  1712.  { "act",     "act help", ActionRtne, IVAL(actI,IO_INT|IO_OPT,FMT_INTS,0) },
  1713.  { "actdisp", "act help", ActionRtne,IVAL(actI,IO_INT|IO_OPT|IO_DSP,FMT_INTS,0)},
  1714.  { "tdouble", "double help", 0, IVAL(Tdouble,IO_FLT,FMT_FLT2,0) },
  1715.  { "tfloat",  "float help",  0, IVAL(Tfloat, IO_FLT,FMT_FLT3,0) },
  1716.  { "tlong",   "long help",   0, IVAL(Tlong,  IO_INT,FMT_INTS,0) },
  1717.  { "tshort",  "short help",  0, IVAL(Tshort, IO_INT,FMT_INTU,0) },
  1718.  { "tchar",   "char help",   0, IVAL(Tchar,  IO_INT,FMT_HEXU,0) },
  1719.  { "tbool",   "bool help",0,IVAL(Tbool,IO_INT|IO_LITONLY,FMT_OCTU,&YesNo[0]) },
  1720.  { "tstr",    "string help", 0, ISTR(Tstr,   IO_STR) },
  1721.  { "tfil",    "file help",   0, ISTR(Tfil,   IO_FNM) },
  1722.  { "tdte",    "date help",   0, ISTR(TDate,  IO_DTE) },
  1723.  { "tfld",    "field help",  0, ISTR(Tfld,   IO_FLD) },
  1724.  { "tarray",  "array help",  0, IVALA(Tarray,IO_INT|IO_OPT,FMT_INTS,0) },
  1725.  { "bit1",    "bit-1 help",  0, IVAL(Bit1,   IO_BIT|IO_LITONLY,FMT_INTS, &Bits[0]) },
  1726.  { "bit2",    "bit-2 help",  0, IVAL(Bit2,   IO_BIT,FMT_INTS, &Bits[0]) },
  1727.  { 0, 0, 0 }
  1728. };
  1729.  
  1730.  
  1731. int MsgER( buf )
  1732. char        *buf;        /* message buffer */
  1733. {
  1734.     fputs( buf, stderr );
  1735.     fputs( buf, stdout );
  1736.     fflush( stdout );
  1737.     return( -1 );
  1738. }
  1739.  
  1740. main(ac,av)
  1741. int         ac;        /* arg counter */
  1742. char        *av[];        /* arg pointer */
  1743. {
  1744.     int         rc;        /* return code */
  1745.     char    *sp;        /* string pointer */
  1746.     char    *wsp;        /* work string pointer */
  1747.     char     buf[80];    /* work buffer */
  1748.  
  1749.     PrintTableI( &cmds[0], stdout, (char *)0, 0 );
  1750.     PrintTableI( &cmds[0], stdout, (char *)0, 1 );
  1751.     for( QuitI = 0; QuitI == 0 ;) {
  1752.     fputs( "Enter Line>", stdout );
  1753.     fflush( stdout );
  1754.     sp = fgets( buf, sizeof(buf), stdin );
  1755.     wsp = sp;
  1756.     rc = ParseLineI( &wsp, &cmds[0], stdout, 1 );    /* syntax check */
  1757.     if ( rc == 0 ) {
  1758.         rc = ParseLineI( &sp, &cmds[0], stdout, 0 );
  1759.         fprintf( stdout, "RC=%d\n", rc );
  1760.         PrintTableI( &cmds[0], stdout, (char *)0, 0 );
  1761.     }
  1762.     }
  1763.  
  1764.     exit( 0 );
  1765. }
  1766. #endif    /* TESTCMD */
  1767.